package pl.elka.pobr.ppr.ui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;

import pl.elka.pobr.ppr.logic.ImageHolder;
import pl.elka.pobr.ppr.logic.ImageProcessor;
import pl.elka.pobr.ppr.logic.ProgressCallback;
import pl.elka.pobr.ppr.utils.FilePickingUtils;
import pl.elka.pobr.ppr.utils.Log;

public class MainFrame extends JFrame implements ProgressCallback {

    private static final String APP_NAME = "POBR Picture Recognition";
    private static final String LOG_TAG = "MainFrame";
    private Dimension mScreenSize;
    private JLabel mStatusLabel;
    private String mLastStatusText;
    private ImageProcessor mImageProcessor;
    private ImageFrame mImageFrame;
    private ImageFrame mAdditionalFrame;
    private ImageHolder mImageHolder;

    public MainFrame() {
        super(APP_NAME);
        mScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setLocation(mScreenSize.width / 6, mScreenSize.height / 6);
        prepareMenu();
        mLastStatusText = "  Idle";
        mStatusLabel = new JLabel(mLastStatusText);
        Container con = getContentPane();
        con.add(mStatusLabel, BorderLayout.SOUTH);
        setSize(300, 120);
        setPreferredSize(new Dimension(300, 120));
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void prepareMenu() {
        JMenu file = new JMenu("File");
        file.setMnemonic('F');
        JMenuItem openItem = new JMenuItem("Open");
        openItem.setMnemonic('O');
        file.add(openItem);
        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.setMnemonic('x');
        file.add(exitItem);
        JMenu actions = new JMenu("Actions");
        actions.setMnemonic('F');
        JMenuItem recogniseItem = new JMenuItem("Recognise");
        recogniseItem.setMnemonic('R');
        actions.add(recogniseItem);
        JMenuItem showItem = new JMenuItem("Show image");
        showItem.setMnemonic('i');
        actions.add(showItem);
        JMenuItem functionsItem = new JMenuItem("Functions");
        functionsItem.setMnemonic('h');
        actions.add(functionsItem);
        JMenuItem stats = new JMenuItem("Statistics");
        stats.setMnemonic('S');
        actions.add(stats);
        openItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                File f = FilePickingUtils.openFileChooser(MainFrame.this);
                if (f != null) {
                    Log.d(LOG_TAG, "Opened file=" + f.getName());
                    try {
                        mImageHolder = new ImageHolder(f);
                        mLastStatusText = "  File=" + f.getName() + ", size=" + mImageHolder.getImageSize().width + "x"
                                + mImageHolder.getImageSize().height;
                        mStatusLabel.setText(mLastStatusText);
                        mImageProcessor = new ImageProcessor(mImageHolder, MainFrame.this);
                        if (mImageFrame != null) {
                            mImageFrame.dispose();
                        }
                        if (mAdditionalFrame != null) {
                            mAdditionalFrame.dispose();
                        }
                        mImageFrame = new ImageFrame(MainFrame.this.getLocationOnScreen(), mImageHolder.getImageSize());
                        mImageFrame.setVisible(true);
                        mImageFrame.refreshViewWithImage(mImageHolder.getImage());
                    } catch (IOException e1) {
                        e1.printStackTrace();
                        JOptionPane.showMessageDialog(MainFrame.this, "Unable to load image: \n" + f.getAbsolutePath(), "Error", JOptionPane.ERROR_MESSAGE);
                    }
                }
            }
        });
        exitItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        // actions menu
        recogniseItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                Log.d(LOG_TAG, "recognise clicked");
                if (mImageProcessor != null) {
                    try {
                        mImageProcessor.processImage();
                    } catch (Exception e1) {
                        e1.printStackTrace();
                        JOptionPane.showMessageDialog(MainFrame.this, e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                    }
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        functionsItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                Log.d(LOG_TAG, "functions list");
                createFunctionListDialog();
            }
        });
        showItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (mImageFrame != null) {
                    mImageFrame.setVisible(true);
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        stats.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                Log.d(LOG_TAG, "stats clicked");
                JOptionPane.showMessageDialog(MainFrame.this, "Not implemented", "Error", JOptionPane.ERROR_MESSAGE);
            }
        });
        JMenuBar bar = new JMenuBar();
        setJMenuBar(bar);
        bar.add(file);
        bar.add(actions);
    }

    private void createFunctionListDialog() {
        JRadioButton histogramButton = new JRadioButton("Show histogram");
        JRadioButton histEqualization = new JRadioButton("Histogram equalization");
        JRadioButton blur = new JRadioButton("Blur");
        JRadioButton sharpen = new JRadioButton("Sharpen");
        histogramButton.setSelected(true);
        ButtonGroup group = new ButtonGroup();
        group.add(histogramButton);
        group.add(histEqualization);
        group.add(blur);
        group.add(sharpen);
        Object[] array = {new JLabel("Select function:"), histogramButton, histEqualization, blur, sharpen};
        int res = JOptionPane.showConfirmDialog(MainFrame.this, array, "Select function", JOptionPane.OK_CANCEL_OPTION);
        // User hit OK
        if (res == JOptionPane.OK_OPTION) {
            Log.d(LOG_TAG, "OK_OPTION");
            // User selected button 1
            if (histogramButton.isSelected()) {
                Log.d(LOG_TAG, "Selected: histogramButton");
                if (mImageProcessor != null) {
                    int[][] hist;
                    hist = mImageProcessor.getHistogramValues();
                    if (hist != null) {
                        new HistogramFrame(hist).setVisible(true);
                    }
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
            // User selected button 2
            if (histEqualization.isSelected()) {
                Log.d(LOG_TAG, "Selected: histEqualization");
                if (mImageProcessor != null) {
                    int[][] hist;
                    hist = mImageProcessor.histogramEqualization();
                    if (hist != null) {
                        new HistogramFrame(hist).setVisible(true);
                    }
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
            // User selected button 3
            if (blur.isSelected()) {
                Log.d(LOG_TAG, "Selected: blur");
                if (mImageProcessor != null) {
                    mImageProcessor.blurImage();
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
            // User selected button 4
            if (sharpen.isSelected()) {
                Log.d(LOG_TAG, "Selected: sharpen");
                if (mImageProcessor != null) {
                    mImageProcessor.sharpenImage(true);
                } else {
                    JOptionPane.showMessageDialog(MainFrame.this, "No image loaded", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
        // User hit CANCEL
        if (res == JOptionPane.CANCEL_OPTION) {
            Log.d(LOG_TAG, "CANCEL_OPTION");
        }
        // User closed the window without hitting any button
        if (res == JOptionPane.CLOSED_OPTION) {
            Log.d(LOG_TAG, "CLOSED_OPTION");
        }
    }

    @Override
    public void updateProgress(float progressValue) {
        Log.d(LOG_TAG, "updateProgress=" + progressValue);
        mStatusLabel.setText("  Progress " + progressValue + "%");
    }

    @Override
    public void calculationError(String errorMessage) {
        Log.d(LOG_TAG, "calculationError=" + errorMessage);
        JOptionPane.showMessageDialog(MainFrame.this, errorMessage, "Error", JOptionPane.ERROR_MESSAGE);
        mStatusLabel.setText(mLastStatusText);
    }

    @Override
    public void calculationFinished(BufferedImage processedImage) {
        Log.d(LOG_TAG, "calculationFinished");
        mStatusLabel.setText(mLastStatusText);
        mImageFrame.refreshViewWithImage(processedImage);
    }

    @Override
    public void calculationFinished(BufferedImage processedImage, boolean createNewWindow) {
        if (createNewWindow) {
            Log.d(LOG_TAG, "calculationFinished with create new window");
            mAdditionalFrame = new ImageFrame(MainFrame.this.getLocationOnScreen(), mImageHolder.getImageSize());
            mAdditionalFrame.setVisible(true);
            mAdditionalFrame.refreshViewWithImage(processedImage);
        } else {
            calculationFinished(processedImage);
        }
    }
}
